package com.fay.designPattern.reflector;

import lombok.Getter;

import javax.transaction.InvalidTransactionException;

/**
 * @Title:
 * @Description:
 * @Author Fay Wang
 * @Date 2022/3/21 19:43
 * @Version 1.0
 */
@Getter
public class Transaction {
    enum STATUS {
        TO_BE_EXECUTED, EXECUTED, EXPIRED, FAILED
    }
    private String id;
    private Long buyerId;
    private Long sellerId;
    private Long productId;
    private String orderId;
    private Long createTimestamp;
    private Double amount;
    private STATUS status;
    private String walletTransactionId;
    private TransactionLock transactionLock;
    private WalletRepService walletRepService;
    private final Long fourteenDays = (long) 14 * 24 * 60 * 60 * 100;

    public void setWalletRepService(WalletRepService service) {
        this.walletRepService = service;
    }

    public void setTransactionLock(TransactionLock lock) {
        this.transactionLock = lock;
    }

    public Transaction(String preAssignedId, Long buyerId, Long sellerId, Long productId, String orderId) {
        if (preAssignedId != null && !preAssignedId.isEmpty()) {
            this.id = preAssignedId;
        } else {
            this.id = IdGenerator.generateTransactionId();
        }
        if (!this.id.startsWith("t_")) {
            this.id = "t_" + preAssignedId;
        }
        this.buyerId = buyerId;
        this.sellerId = sellerId;
        this.productId = productId;
        this.orderId = orderId;
        this.status = STATUS.TO_BE_EXECUTED;
        this.createTimestamp = System.currentTimeMillis();
    }

    protected boolean isExpired() {
        long executionInvokedTimestamp = System.currentTimeMillis();
        return executionInvokedTimestamp - createTimestamp > fourteenDays;
    }

    public boolean execute() throws InvalidTransactionException {
        if ((buyerId == null || (sellerId == null) || amount < 0.0)) {
            throw new InvalidTransactionException();
        }
        if (status == STATUS.EXECUTED) {
            return true;
        }
        boolean isLocked = false;
        try{
            isLocked = transactionLock.lock(id);
            if (!isLocked) {
                return false;//锁定未成功，返回false，job兜底执行
            }
            if (status == STATUS.EXECUTED) {
                return true;// double check
            }
            if (isExpired()) {
                this.status = STATUS.EXPIRED;
                return false;
            }
            String walletTransactionId = walletRepService.moveMoney(id, buyerId, sellerId);
            if (walletTransactionId != null) {
                this.walletTransactionId = walletTransactionId;
                this.status = STATUS.EXECUTED;
                return true;
            } else {
                this.status = STATUS.FAILED;
                return false;
            }
        }finally {
            if (isLocked) {
                transactionLock.unlock();
            }
        }
    }
    static class IdGenerator {
        public static String generateTransactionId() {
            return "";
        }
    }
}
